package legumes.client.ui.widgets.window;

import java.util.List;

import legumes.client.resources.PNResources;
import legumes.client.ui.util.wrapper.LatLngWrapper;
import legumes.client.ui.widgets.map.MapDrawingCircleUtils;
import legumes.client.ui.widgets.map.MapFactory;
import legumes.shared.domain.HomePlaceDelivery;
import legumes.shared.domain.PlaceDelivery;

import com.google.gwt.ajaxloader.client.AjaxLoader;
import com.google.gwt.ajaxloader.client.ClientLocation;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.maps.client.InfoWindow;
import com.google.gwt.maps.client.InfoWindowContent;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.control.LargeMapControl;
import com.google.gwt.maps.client.control.MapTypeControl;
import com.google.gwt.maps.client.event.MapDragEndHandler;
import com.google.gwt.maps.client.event.MapZoomEndHandler;
import com.google.gwt.maps.client.event.MarkerClickHandler;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.overlay.Icon;
import com.google.gwt.maps.client.overlay.Marker;
import com.google.gwt.maps.client.overlay.MarkerOptions;
import com.google.gwt.user.client.ui.FlowPanel;

public class PlacesDeliveryMapPanel extends FlowPanel {
	private MapWidget map;
	private int windowHeight;
	private int windowWidth;
	private List<PlaceDelivery> pdList;
	private PlaceDelivery selectedPlaceDelivery;
	private InfoWindow selectedPlaceDeliveryDetailsInfoWindow;
	private MapDrawingCircleUtils mapDrawingCircleUtils;
	
	public PlacesDeliveryMapPanel(int windowWidth_, int windowHeight_, 
			final LatLng clLatLng_, List<PlaceDelivery> pdAr_) {
		super();
		pdList = pdAr_;
		if(windowHeight_>0){
			windowHeight = windowHeight_;
		} else {
			windowHeight = com.google.gwt.user.client.Window.getClientHeight();
		}
		
		windowWidth = windowWidth_;
		
		/*
		 * Asynchronously loads the Maps API.
		 * 
		 * The first parameter should be a valid Maps API Key to deploy this
		 * application on a public server, but a blank key will work for an
		 * application served from localhost.
		 */
		MapFactory.getInstance().loadMapLibrary(
				new Runnable() {
					public void run() {
						buildUi(clLatLng_);
					}
				}
		);
	}
	
	protected void initWindowProperties(){}
	
	protected void initMapControls(){
		getMapWidget().addControl(new LargeMapControl());
		getMapWidget().addControl(new MapTypeControl());
	}
	
	private void buildUi(LatLng clLatLng_) {
		LatLng clLatLng  = clLatLng_;
		if(clLatLng==null){
			ClientLocation cl = AjaxLoader.getClientLocation();
			clLatLng = cl!=null?
					LatLng.newInstance(cl.getLatitude(), cl.getLongitude()):
						LatLng.newInstance(43,1.4)	;
		}
		
		map = MapFactory.getInstance().createMapWidgetWithoutCtrl(clLatLng, windowWidth-30, windowHeight-40);
		initMapControls();
		getMapWidget().addMapZoomEndHandler(new MapZoomEndHandler(){

			@Override
			public void onZoomEnd(MapZoomEndEvent event) {
				refreshStoreList();
			}
			
		});
		getMapWidget().addMapDragEndHandler(new MapDragEndHandler(){

			@Override
			public void onDragEnd(MapDragEndEvent event) {
				refreshStoreList();
			}
			
		});
		add( getMapWidget() );
		refreshPlacesDeliveryListDeferred();
	}
	
	public void refreshPlacesDeliveryListDeferred(){
		//Defer in order to let time to the map to initialized its bound
		// and so to refresh the store list in function of the store bound
		Scheduler.get().scheduleDeferred(new ScheduledCommand() {
		      public void execute() {
		    	  refreshStoreList();
		      }
		    }
		);
	}
	public void refreshStoreList(){
		getMapWidget().clearOverlays();

		for(final PlaceDelivery pl : pdList){
			getMapWidget().addOverlay(createPlaceDeliveryMarker(pl));
		}
	}
	
	private Marker createPlaceDeliveryMarker(final PlaceDelivery pd_){
		MarkerOptions markerOptions = MarkerOptions.newInstance();
		markerOptions.setTitle(pd_.getTitle());
		final boolean isAnHomePlaceDelivery = pd_ instanceof HomePlaceDelivery;
		Icon ic = Icon.DEFAULT_ICON;
		if(isAnHomePlaceDelivery){
			ic.setImageURL( PNResources.INSTANCE.gmapDeliveringAtHomeIcon().getURL() );
		} else {
			ic.setImageURL( PNResources.INSTANCE.gmapDeliveringAtMarketIcon().getURL() );
		}
		markerOptions.setIcon( ic );
			
		final LatLng centLatLng = LatLngWrapper.converLatLng(pd_.getLatLng());
		
		final Marker marker = new Marker(centLatLng);
		marker.setDraggingEnabled(false);
		marker.addMarkerClickHandler(new MarkerClickHandler(){

			@Override
			public void onClick(MarkerClickEvent event) {
				onPlaceDeliveryClicked(pd_, isAnHomePlaceDelivery, centLatLng);
			}

		});
		return marker;
	}
	
	protected void drawHomePlaceDeliveryArea(PlaceDelivery pl_){
		int radius = ((HomePlaceDelivery)pl_).getRadiusKm();
		new MapDrawingCircleUtils(getMapWidget(), LatLngWrapper.converLatLng(pl_.getLatLng()), radius).drawCircle();
	}
	
	protected void showInfoWindow(PlaceDelivery pl_){
		getMapWidget().getInfoWindow().open(map.getCenter(),
				new InfoWindowContent(
						pl_.toString() ));
	}
	
	protected void onPlaceDeliveryClicked(PlaceDelivery pl_, boolean isAnHomePlaceDelivery_, LatLng centLatLng_){
		selectedPlaceDelivery = pl_;
		onPlaceDeliverySelected(selectedPlaceDelivery);
	}
	
	protected void onPlaceDeliverySelected(PlaceDelivery pl_){
		
		if(mapDrawingCircleUtils!=null){
			mapDrawingCircleUtils.clearCreatedMapOverlays();
		}
		
		if( pl_ instanceof HomePlaceDelivery){
			mapDrawingCircleUtils = new MapDrawingCircleUtils(getMapWidget(), 
					LatLngWrapper.converLatLng(pl_.getLatLng()), 
					((HomePlaceDelivery) pl_).getRadiusKm(),
					false);
			mapDrawingCircleUtils.drawCircle();
		}
		
		if(selectedPlaceDeliveryDetailsInfoWindow==null){
			selectedPlaceDeliveryDetailsInfoWindow = getMapWidget().getInfoWindow();
		}
		InfoWindowContent infoWindowContent = new InfoWindowContent(
				pl_.toHTMLString());
		infoWindowContent.setMaxWidth(200);
		selectedPlaceDeliveryDetailsInfoWindow.open(
				LatLngWrapper.converLatLng(pl_.getLatLng()), 
				infoWindowContent );
	}
	
	public MapWidget getMapWidget(){
		return map;
	}
}
